#ifndef SQUARE_HH_
#define SQUARE_HH_
#include <vector>
#include <ostream>
#include <cstdlib>
#include <cstring>


/*
    struct for representing a square in the grid.
*/
struct Square
{
  signed ant : 8;
  signed hillPlayer : 8;

  bool isVisible : 1;
  bool wasVisible : 1;
  bool isWater : 1;
  bool isHill : 1;
  bool isFood : 1;
  bool wasDead : 1;
  bool wasKilled : 1;
  bool wasVisited : 1;
  unsigned neighbours : 4;
  unsigned : 0; // packed


  Square() :
    ant(-1),
    hillPlayer(-1),
    isVisible(false),
    wasVisible(false),
    isWater(false),
    isHill(false),
    isFood(false),
    wasDead(false),
    wasKilled(false),
    wasVisited(false),
    neighbours(0)
  { }

  bool operator==(const Square & b)
  {
    return memcmp(this, &b,sizeof(Square)) == 0;
  }
  bool operator!=(const Square & b)
  {
    return memcmp(this, &b,sizeof(Square)) != 0;
  }

  //resets the information for the square except water information
  void reset_all(void)
  {
    ant = hillPlayer = -1;
    isVisible = false;
    // keep wasVisible
    // keep isWater
    isHill = false;
    isFood = false;
    wasDead = false;
    // keep wasVisited
    neighbours = 0;
  }


  //resets only ants food and hills
  void reset_unstable(void)
  {
    ant = hillPlayer = -1;
    // kepp isVisible
    // keep wasVisible
    // keep isWater
    //isHill = false;
    //isFood = false;
    // keep wasDead;
    wasKilled = false;
    // keep wasVisited
    // keep neighbours = 0;
  }



  std::ostream & dump(std::ostream & os) const
  {
    if(isWater)
      os << '%';
    else if(isFood)
      os << '*';
    else if(isHill)
      os << (char)('A' + hillPlayer);
    else if(ant != -1)
      os << (char)('a' + ant);
    else if(isVisible)
      {
	//if(neighbours!=0)
	//os << (char)('0' + neighbours);
	//else
	  os << '.';
      }
    else if(wasVisible)
      {
	if(wasDead)
	  os << '+';
	else
	  os << '-';
      }
    else
      {
	os << '?';
      }
    return os;
  }

};


//check if locally walkable position
inline bool isLocallyWalkable(Square & sq)
{
  return not sq.isWater and sq.wasVisible;
}


//check if globally walkable position
inline bool isGloballyWalkable(Square & sq)
{
  return not sq.isWater;
}




//check if friend position
inline bool wasNotVisited(Square & sq)
{
  return not sq.wasVisited;
}



//check if friend position
inline bool isUnexplored(Square & sq)
{
  return (not sq.isVisible) and (not sq.wasVisible);
}


//check if friend position
inline bool isInvisible(Square & sq)
{
  return not sq.isVisible;
}





//check if friend position
inline bool isFriend(Square & sq, signed team = 0)
{
  return sq.ant==team;
}


//check if friend position
inline bool isGround(Square & sq)
{
  return not sq.isWater and sq.ant==-1;
}


//check if enemy position
inline bool isEnemy(Square & sq, signed team = 0)
{
  return sq.ant!=-1 and sq.ant!=team;
}


//check if enemy position
inline bool mayBeEnemy(Square & sq, signed team)
{
  if(team!=0)
    return sq.ant!=-1 and sq.ant!=team;
  else
    return not sq.isVisible or (sq.ant!=-1 and sq.ant!=team);
}



std::ostream & operator<<(std::ostream & os, const Square & sq);


#endif //SQUARE_HH_
